<html>

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no">
    <script src="./asr.min.js"></script>
</head>
<style type="text/css">
    body {
        margin: 0;
        padding: 0;
    }
    .main {
        font-family: Arial, sans-serif;
        font-size: 16px;
        line-height: 1.5;
        display: flex;
        flex-direction: column;
        width: 100%;
    }

    .form {
        margin: 4px;
        text-align: left;
    }
    textarea, input[type='text'] {
        width: 100%;
        padding: 3px;
    }
</style>

<body>
    <div class="main">
        <div class="form">
            <label for="auto"><input id="auto" type="checkbox" />自动采集</label>
            <label for="emo"><input id="emo" type="checkbox" checked />情绪感知</label>
            <label for="denoise"><input id="denoise" type="checkbox" checked />降噪处理</label>
            <button id="captureBtn">按下采集</button>
        </div>
        <div class="form" style="font-size:12px;color:#e91e63">
            <input id="hotword" type="text" placeholder="请输入热词多个热词请用空格分隔" />
            <br>
            注：启用热词模式将使推理时间变长
        </div>
        <div class="form">
            <textarea id="result" rows="16"></textarea>
        </div>
    </div>
    <script>
        var isInit = false;
        const hotword = document.getElementById('hotword');
        const autoCheckbox = document.getElementById('auto');
        const emoCheckbox = document.getElementById('emo');
        const denoiseCheckbox = document.getElementById('denoise');
        const captureBtn = document.getElementById('captureBtn');
        const resultBox = document.getElementById('result');
        const audio = new Audio();
        this.config = {
            mute: false,                // 静音
            audio: "",                  // 音频流
            status1Text: '',            // 麦克风段状态
            status2Text: '',            // 喇叭端状态（因为只是ASR所以这个暂未实际使用）
            step: 0,                    // 0-设置模式，1-ASR模式
            // hotword: "",                // 热词
            // emo: true,                  // 情感分析
            // denoise: true,              // 降噪
            wsSer: {                    // webSocket端
                uri: `${location.protocol === 'https:' ? "wss:" : "ws:"}//${location.host}/ws/asr/`, // 服务端地址
                talkId: null,           // 会话ID
            },
            showMessage: (...args) => { // 消息回调
                console.log(args);
                resultBox.innerHTML = args;
            },
            splitMode: {
                mode: "end",            // end-自然停顿，split-定時切片（慎用）
                duration: 1,            // 自然停顿的切片时间，单位秒
                activateVolume: 10,     // 自然停顿的激活音量，即低于这个音量则视为说话结束
            },
            initMedia() {               // 初始化媒体流
                mediaLib.unInit();
                mediaLib.init(
                    top.config.audio,
                    null,
                    null,
                    "base64"
                );
            },
            disconnect() {              // 断开连接
                top.config.cancel = true;
                if (top.config.ws) {
                    top.config.ws.close();
                }
            },
            reConnect() {               // 重连
                if (top.config.cancel === true) return;
                top.config.status1Text = "reConnecting...";
                top.config.status2Text = top.config.status1Text;
                top.config.showMessage('status1Text', top.config.status1Text);
                top.config.showMessage('status2Text', top.config.status1Text);
                top.config.loading = true;
                top.config.cancel = true;
                setTimeout(() => {
                    top.config.connect();
                }, 3000);
            },
            connect() {                 // 连接
                top.config.disconnect();
                if (this.config?.ws?.timeout) clearTimeout(top.config.ws.timeout)
                top.config.wsSer.talkId = mediaLib.uuid();
                let uri = top.config.wsSer.uri + top.config.wsSer.talkId;
                /*if (top.config.denoise) {
                    uri = `${uri}/denoise?spker=${top.config.spker}`
                }*/
                console.log(uri)
                top.config.ws = new WebSocket(uri);
                top.config.ws.timeout = setTimeout(() => {
                    top.config.ws.close();
                    top.config.cancel = false;
                    top.config.reConnect();
                }, 5000)
                top.config.ws.onopen = () => {
                    if (this?.ws?.timeout) clearTimeout(top.config.ws.timeout)
                    top.config.status1Text = "Connected";
                    top.config.status2Text = top.config.status1Text;
                    top.config.loading = false;
                    top.config.ws.send(1);
                };

                top.config.ws.onmessage = (event) => {
                    // 接收ASR服务端的返回信息
                    let message = event.data;
                    top.config.status1Text = 'success'
                    top.config.showMessage(message);
                };

                top.config.ws.onerror = (error) => {
                    top.config.reConnect();
                };

                top.config.ws.onclose = () => {
                    top.config.reConnect();
                };
            },
            next() {
                top.config.step++;
                top.config.loading = true;
                mediaLib.unInit();
                if (top.config.step === 1) {
                    top.config.connect();
                }
                setTimeout(() => {
                    mediaLib.init(
                        top.config.audio,
                        null,
                        null,
                        "base64"
                    );
                    autoChange(autoCheckbox)
                }, 500);
            },
            getVideo() {
                let video = undefined;
                video = document.querySelector('video');
                return video;
            },
            getVol(vol) {
                let val = vol / 50;
                if (val > 1) val = 1;
                return val;
            },
            setMute() {
                top.config.mute = !top.config.mute;
                if (top.config.mute === true) {
                    top.config.status1Text = "Mute";
                }
                mediaLib.setMute(top.config.mute);
            },
        }
        var mediaLib;
        mediaLib = new micLib({
            splitMode: top.config.splitMode,
            output: "base64", //blob, blobURI(默认), base64, all
            onError: (error) => {               // 错误回调
                top.config.showMessage('sys', `onError`, JSON.stringify(error));
            },
            onInit: (media) => {
                top.config.showMessage('sys', `onInit`, media);
                top.config.audio = media.audioId;
                top.config.video = media.videoId;
                top.config.loading = false;
            },
            onUnInit: () => {                   // 释放媒体流
                top.config.showMessage('sys', `onUnInit`);
            },
            onStart: () => {                    // 开始采集
                top.config.showMessage('sys', `onStart`);
            },
            onStop: () => {                     // 停止采集
                top.config.showMessage('sys', `onStop`);
            },
            onMicVolume: ({ vol, vol2 }) => {   // 麦克风音量
                top.config.percentage = vol2;
                //top.config.showMessage('sys', "onMicVolume", vol, vol2);
            },
            onAudioStart: () => {
                if (top.config.step === 1) {    // 录音模式下开始播放录音
                    top.config.showMessage('sys', "speaking...", '0');
                }
            },
            onAudioEnd: () => {
                if (top.config.step === 1) {    // 录音模式下录音结束
                    top.config.showMessage('sys', "success");
                }
            },
            onAudioVolume: (vol) => {           // 播放录音的音量
                top.config.percentage2 = vol;
                top.config.showMessage('sys', "onAudioVolume", vol);
            },
            onTalkStart: (sessionId) => {       // 开始采集语音
                top.config.showMessage('log', "开始采集语音", sessionId);
                top.config.showMessage('sys', "speaking...", '1');
            },
            onTalkEnd: ({ sessionId, blob, blobURI, base64, hasNew }) => { // 结束采集语音
                top.config.showMessage('log', "停止采集语音", sessionId); //, base64);
                if (top.config.step === 0) {
                    mediaLib.playRec(base64);
                } else {
                    if (top.config.ws) {
                        top.config.status1Text = "recognition...";
                        setTimeout(() => {
                            if (top.config.status1Text === "recognition...") top.config.status1Text = "Ready";
                        }, 2000);
                        if (base64) {
                            if (base64.length < 500) {
                                setTimeout(() => {
                                    top.config.status1Text = 'Recognition error'
                                }, 2000)
                                top.config.showMessage('音頻太短，對話無效，請嘗試發音清晰', 'user', 'error');
                                return;
                            } else {
                                msg = {
                                    input: base64,
                                    denoise: denoiseCheckbox.checked === true,
                                    hotword: hotword.value,
                                    emo: emoCheckbox.checked === true,
                                }
                                top.config.ws.send(JSON.stringify(msg));
                            }
                        }
                    }
                }
            },
            autoStart: true,
            autoInit: true,
        });
        // mediaLib.init(null, null, top.config.getVideo());
        top.config.next();
        function autoChange(obj) {
            if (obj.checked) {
                mediaLib.setSplitMode(
                    top.config.splitMode
                )
            } else {
                mediaLib.setSplitMode({
                    mode: "end",            // end-自然停顿，split-定時切片（慎用）
                    duration: 1000,         // 自然停顿的切片时间，单位秒
                    activateVolume: 0,      // 自然停顿的激活音量，即低于这个音量则视为说话结束
                })
            }
            top.config.setMute(!obj.checked)
            captureBtn.disabled = obj.checked;
        }
        window.onload = () => {
            autoCheckbox.addEventListener('change', e => autoChange(e.target));
            // 添加事件监听器
            captureBtn.addEventListener('mousedown', handleEvent);
            captureBtn.addEventListener('touchstart', handleEvent);
            captureBtn.addEventListener('mouseup', handleEvent);
            captureBtn.addEventListener('touchend', handleEvent);
            captureBtn.addEventListener('mouseout', handleEvent);
        }
        function handleEvent(event) {
            // 阻止默认行为，例如触摸屏上的滚动
            event.preventDefault();
            // 根据事件类型执行不同的操作
            switch (event.type) {
                case 'mousedown':
                case 'touchstart':
                    event.target.setAttribute('downstart', 1);
                    top.config.setMute(true);
                    break;
                case 'mouseup':
                case 'touchend':
                    event.target.removeAttribute('downstart');
                    top.config.setMute(false);
                    break;
                case 'mouseout':
                    if (event.target.getAttribute('downstart') == '1') {
                        event.target.removeAttribute('downstart')
                        top.config.setMute(false);
                    }
                    break;
            }
        }
    </script>
</body>

</html>